use std::{ops::Deref, sync::Arc};

use axum::{
    routing::{get, post},
    Router,
};
use serde::Deserialize;

use crate::{
    error::AppErr,
    global::APP,
    robot::{self, adj, RobotStatus},
    serve::utils::{Cbor, Void},
};

use super::{cbor_ok, CborRet};

async fn on_is_connect() -> Cbor<bool> {
    let ret = robot::is_connect().await;
    Cbor(ret)
}

async fn on_connect(ip: Cbor<String>) -> Result<Void, AppErr> {
    robot::connect(ip.deref()).await?;
    Ok(Void)
}

async fn on_adj_start(name: Cbor<String>) -> Result<Void, AppErr> {
    adj::adj_start(name.0).await?;
    Ok(Void)
}

async fn on_adj_finish() -> Result<Void, AppErr> {
    adj::adj_save().await?;
    Ok(Void)
}

#[derive(Debug, Deserialize)]
struct MoveJArg {
    speed: f32,
    acc: f32,
    bland_t: f32,
}

async fn on_adj_cur_movej(arg: Cbor<MoveJArg>) -> Result<Void, AppErr> {
    adj::adj_movej_cur(arg.speed, arg.acc, arg.bland_t).await?;
    Ok(Void)
}

#[derive(Debug, Deserialize)]
struct MoveLArg {
    speed: f32,
    acc: f32,
    bland_r: f32,
}

async fn on_adj_cur_movel(arg: Cbor<MoveLArg>) -> Result<Void, AppErr> {
    adj::adj_movel_cur(arg.speed, arg.acc, arg.bland_r).await?;
    Ok(Void)
}

#[derive(Debug, Deserialize)]
struct JawArg {
    pos: i32,
    tor: i32,
}

async fn on_adj_jaw(arg: Cbor<JawArg>) -> Result<Void, AppErr> {
    adj::adj_jaw(arg.pos, arg.tor).await?;
    Ok(Void)
}

async fn on_current_status() -> CborRet<Arc<RobotStatus>> {
    let status = APP.robot_status().await.ok_or(AppErr::Static("没用状态"))?;
    cbor_ok(status)
}

pub fn register() -> Router {
    Router::new()
        .route("/is_connect", get(on_is_connect))
        .route("/connect", post(on_connect))
        .route("/adj_start", post(on_adj_start))
        .route("/adj_finish", post(on_adj_finish))
        .route("/adj_movej", post(on_adj_cur_movej))
        .route("/adj_movel", post(on_adj_cur_movel))
        .route("/adj_jaw", post(on_adj_jaw))
        .route("/current_status", get(on_current_status))
}
